#!/usr/bin/ruby

require "opengl"
require "glut"

class Frame
	attr_accessor :coop, :tft
	def self.single_from_file(file=$stdin)
		f = Frame.new
		line = file.gets
		return nil unless line
		strategy = line.split(/\s+/).map!{|s| s.to_f}
		file.gets #f.fitness = file.gets.split(/\s+/).map!{|s| s.to_f}
		s = 0.0
		t = 0.0
		strategy.each do |st| 
			s += [st,0].max 
			t += 1.0 if st == -2.0
		end
		f.coop = s/strategy.size
		f.tft  = t/strategy.size
		file.gets
		f
	end
	def self.skip(file=$stdin)
		file.gets
		file.gets
		file.gets
	end
	def self.multiple_from_file(file=$stdin)
		result = []
		until file.eof? do
			result << self.single_from_file(file)
			print "\r#{result.size}"
			$nth.times do self.skip(file) end
		end
		print "\rwczytano #{result.size} epok\n"
		result
	end
end

class Simulation
	attr_accessor :data, :w, :h

	def self.mkdata(coop, tft)
		data = []
		n = [coop.size,tft.size].min
		n3 = n*3
		n.times do |x|
			100.times do |y|
				x3_yn3 = x*3+y*n3
				if y < coop[x]*100 then
					data[x3_yn3+0] = 0.0 # R
					data[x3_yn3+1] = 0.0 # G
					data[x3_yn3+2] = 0.0 # B
				elsif y < (coop[x]+tft[x])*100 then
					data[x3_yn3+0] = 1.0 # R
					data[x3_yn3+1] = 0.0 # G
					data[x3_yn3+2] = 0.0 # B
				else
					data[x3_yn3+0] = 1.0 # R
					data[x3_yn3+1] = 1.0 # G
					data[x3_yn3+2] = 1.0 # B
				end
			end
		end
		data.pack("f*")
	end

	def self.scan(filename)
		result = self.new
		begin
			file = File.open(filename, "r")
			width, height, type = file.gets.split(/\s+/)
			width, height = width.to_i, height.to_i
			file.gets
			coop = []
			tft = []
			while frame = Frame.single_from_file(file) do
				print "\r#{coop.size}"
				coop << frame.coop
				tft << frame.tft
			end
			result.h = 100
			result.w = [coop.size, tft.size].min
			result.data = mkdata(coop, tft)
			file.close if file
			print "\rwczytano #{result.w} epok\n"
		rescue
			print "\rblad\n"
			result = nil
		end
		result
	end
end

$width = 0
$height = 0
$window_width = 500
$window_height = 500
$nth = [(ARGV[1] || 1).to_i,1].max - 1

$fullscreen = false

$display = Proc.new do
	GL.Clear(GL::COLOR_BUFFER_BIT);
	GL.RasterPos2i(0, 0);
	nh = $basenames.size*$graphs.size
	nw = $probabilities.size
	nh.times do |y|
		next unless $tab[y]
		nw.times do |x|
			s = $tab[y][x]
			next unless s
			GL.PixelZoom(($window_width.to_f/nw.to_f-4.0)/s.w.to_f, ($window_height.to_f/nh.to_f-4.0)/s.h.to_f)
			GL.RasterPos2i((x*$window_width).to_f/(nw).to_f + 2.5, ((nh-1-y)*$window_height).to_f/(nh).to_f + 2.5);
			GL.DrawPixels(s.w, s.h, GL::RGB, GL::FLOAT, s.data);
		end
	end
	
	GLUT.SwapBuffers(); #GL.Flush();
end

$reshape = Proc.new do |w, h|
	GL.Viewport(0, 0, w,  h);
	GL.MatrixMode(GL::PROJECTION);
	GL.LoadIdentity();
	GL.Ortho(0, w, 0, h, -1.0, 1.0);
	GL.MatrixMode(GL::MODELVIEW);
	$window_width = w
	$window_height = h
end

$keyboard = Proc.new do |key, x, y|
	case (key)
	when 27 then exit 0
	when ?q then exit 0
	when ?f then 
		$fullscreen = ! $fullscreen
		if $fullscreen then 
			GLUT.FullScreen 
		else 
			GLUT.PositionWindow(100,100) 
			$window_width = 800
			$window_height = [[$window_width*$graphs.size*$basenames.size/$probabilities.size/2,100].max,600].min	
			GLUT.ReshapeWindow($window_width,$window_height)
		end
	end
	GLUT.PostRedisplay
end

$timerfunc = Proc.new do |param|
	$basenames.each do |basename|
	$graphs.each do |g|
		$tab << []
	$probabilities.size.times do |ii|
		p = $probabilities[ii]
		print "wczytuje #{basename % [p,g]} -> (#{$tab.size-1},#{ii})\n"
		$tab[-1][ii] = Simulation.scan(basename % [p,g])
		$display.call
		GLUT.PostRedisplay
	end
	end
	end
	exit 0 if GLUT.GetWindow == 0
	GLUT.TimerFunc(100,$timerfunc2,0)
end

$timerfunc2 = Proc.new do |param|
	exit 0 if GLUT.GetWindow == 0
	GLUT.TimerFunc(100,$timerfunc2,0)
end

def main
	$basenames = []
	$probabilities = []
	$graphs = []
	Dir["*"].each do |filename|
		filename.scan(/^(.*)_(0\.\d+)_([124689])\.(txt[^\.]*)$/).each do |s|
			base, p, g, ext = s
			name = "#{base}_%s_%s.#{ext}"
			$basenames << name
			$probabilities << p
			$graphs << g
		end
	end
	$basenames.uniq!
	$basenames.sort!
	$probabilities.uniq!
	$probabilities.sort!{|x,y| x.to_f <=> y.to_f}
	$graphs.uniq!
	$graphs.sort!{|x,y| x.to_i <=> y.to_i}

	$window_width = 800
	$window_height = [[$window_width*$graphs.size*$basenames.size/$probabilities.size/2,100].max,600].min
	
	if $basenames.empty? then
		print "No files found\n"
		exit
	end
	$tab = []
	
	GLUT.Init
	GLUT.InitDisplayMode(GLUT::DOUBLE | GLUT::RGB | GLUT::DEPTH);
	GLUT.InitWindowSize($window_width, $window_height);
	GLUT.InitWindowPosition(100, 100);
	GLUT.CreateWindow("KoVis : #{Dir.pwd}");
	GL.PixelStorei(GL::UNPACK_ALIGNMENT, 1);
	GL.ClearColor(0.75, 0.75, 0.75, 0.0);
	GLUT.ReshapeFunc($reshape);
	GLUT.KeyboardFunc($keyboard);
	GLUT.DisplayFunc($display);
	GLUT.TimerFunc(100,$timerfunc,0);
	GLUT.MainLoop();
end

main
